From 43c12534eca2525b593716bc8c75bcb2d15e72f8 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 22 Jul 2003 13:25:32 +0000 Subject: [PATCH] bitkeeper revision 1.372 (3f1d3b4c5vpfm6WgqbVfZVhO04znVw) time.h, keyhandler.c, ac_timer.c, time.c, nmi.c, apic.c: Clean ups. --- xen/arch/i386/apic.c | 15 +- xen/arch/i386/nmi.c | 23 +-- xen/arch/i386/time.c | 303 +++++++++++++++--------------------- xen/common/ac_timer.c | 141 +++++++---------- xen/common/keyhandler.c | 2 - xen/include/asm-i386/time.h | 30 +--- 6 files changed, 204 insertions(+), 310 deletions(-) diff --git a/xen/arch/i386/apic.c b/xen/arch/i386/apic.c index 7710eaa803..ad17799601 100644 --- a/xen/arch/i386/apic.c +++ b/xen/arch/i386/apic.c @@ -581,7 +581,7 @@ int __init calibrate_APIC_clock(void) int i; const int LOOPS = HZ/10; - printk("calibrating APIC timer for CPU%d...\n", smp_processor_id()); + printk("Calibrating APIC timer for CPU%d...\n", smp_processor_id()); /* Put whatever arbitrary (but long enough) timeout * value into the APIC clock, we just want to get the @@ -611,12 +611,12 @@ int __init calibrate_APIC_clock(void) result = (tt1-tt2)*APIC_DIVISOR/LOOPS; printk("..... CPU speed is %ld.%04ld MHz.\n", - ((long)(t2-t1)/LOOPS)/(1000000/HZ), - ((long)(t2-t1)/LOOPS)%(1000000/HZ)); + ((long)(t2-t1)/LOOPS) / (1000000/HZ), + ((long)(t2-t1)/LOOPS) % (1000000/HZ)); printk("..... Bus speed is %ld.%04ld MHz.\n", - result/(1000000/HZ), - result%(1000000/HZ)); + result / (1000000/HZ), + result % (1000000/HZ)); cpu_freq = (u64)(((t2-t1)/LOOPS)*HZ); @@ -625,10 +625,7 @@ int __init calibrate_APIC_clock(void) bus_cycle = (u32) (1000000000000LL/bus_freq); /* in pico seconds */ bus_scale = (1000*262144)/bus_cycle; - /* print results */ - printk("..... bus_freq = %u Hz\n", bus_freq); - printk("..... bus_cycle = %u ps\n", bus_cycle); - printk("..... bus_scale = %u \n", bus_scale); + printk("..... bus_scale = 0x%08X\n", bus_scale); /* reset APIC to zero timeout value */ __setup_APIC_LVTT(0); return result; diff --git a/xen/arch/i386/nmi.c b/xen/arch/i386/nmi.c index 7062e56865..7b338a98d9 100644 --- a/xen/arch/i386/nmi.c +++ b/xen/arch/i386/nmi.c @@ -93,29 +93,33 @@ int __init check_nmi_watchdog (void) unsigned int prev_nmi_count[NR_CPUS]; int j, cpu; - if (!nmi_watchdog) + if ( !nmi_watchdog ) return 0; - printk("testing NMI watchdog ---\n"); + printk("Testing NMI watchdog --- "); - for (j = 0; j < smp_num_cpus; j++) { + for ( j = 0; j < smp_num_cpus; j++ ) + { cpu = cpu_logical_map(j); prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count; } sti(); mdelay((10*1000)/nmi_hz); /* wait 10 ticks */ - for (j = 0; j < smp_num_cpus; j++) { + for ( j = 0; j < smp_num_cpus; j++ ) + { cpu = cpu_logical_map(j); - if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) - printk("CPU#%d: NMI stuck?\n", cpu); + if ( nmi_count(cpu) - prev_nmi_count[cpu] <= 5 ) + printk("CPU#%d stuck. ", cpu); else - printk("CPU#%d: NMI okay\n", cpu); + printk("CPU#%d okay. ", cpu); } + printk("\n"); + /* now that we know it works we can reduce NMI frequency to something more reasonable; makes a difference in some configs */ - if (nmi_watchdog == NMI_LOCAL_APIC) + if ( nmi_watchdog == NMI_LOCAL_APIC ) nmi_hz = 1; return 0; @@ -132,8 +136,7 @@ static inline void nmi_pm_init(void) { } static void __pminit clear_msr_range(unsigned int base, unsigned int n) { unsigned int i; - - for(i = 0; i < n; ++i) + for ( i = 0; i < n; i++ ) wrmsr(base+i, 0, 0); } diff --git a/xen/arch/i386/time.c b/xen/arch/i386/time.c index b0159250c2..7d34bb4098 100644 --- a/xen/arch/i386/time.c +++ b/xen/arch/i386/time.c @@ -1,22 +1,16 @@ /* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- **************************************************************************** - * (C) 2002 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2002-2003 University of Cambridge **************************************************************************** * * File: i386/time.c - * Author: - * Changes: - * - * Date: Jan 2003 + * Author: Rolf Neugebar & Keir Fraser * * Environment: Xen Hypervisor * Description: modified version of Linux' time.c * implements system and wall clock time. * based on freebsd's implementation. - * - **************************************************************************** - * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $ - **************************************************************************** */ /* @@ -49,27 +43,47 @@ #define TRC(_x) #endif +/* GLOBALS */ + unsigned long cpu_khz; /* Detected as we calibrate the TSC */ unsigned long ticks_per_usec; /* TSC ticks per microsecond. */ +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +int timer_ack = 0; -/* We use this to prevent overflow of 31-bit RDTSC "diffs". */ -static unsigned int rdtsc_bitshift; +/* PRIVATE */ -spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +static unsigned int rdtsc_bitshift; /* Which 32 bits of TSC do we use? */ +static unsigned long init_cmos_time; /* RTC time when system time == 0 */ +static u64 cpu_freqs[3]; /* Slow/correct/fast CPU freqs */ +static u32 st_scale_f; /* Cycles -> ns, fractional part */ +static u32 st_scale_i; /* Cycles -> ns, integer part */ +static struct ac_timer update_timer; /* Periodic 'time update' function */ +static spinlock_t stime_lock; /* Lock for accessing sys & wc time */ +struct timeval wall_clock_time; /* WC time at last 'time update' */ +static u32 tsc_irq; /* CPU0's TSC at last 'time update' */ +static s_time_t stime_irq; /* System time at last 'time update' */ -int timer_ack=0; -extern spinlock_t i8259A_lock; -static inline void do_timer_interrupt(int irq, - void *dev_id, struct pt_regs *regs) +/* + * The scale update period is not a whole number of seconds since we want to + * avoid being in sync with the CMOS update-in-progress flag. + */ +#define SCALE_UPDATE_PERIOD MILLISECS(50200) +#define TIME_UPDATE_PERIOD MILLISECS(200) + + +static inline void do_timer_interrupt( + int irq, void *dev_id, struct pt_regs *regs) { #ifdef CONFIG_X86_IO_APIC - if (timer_ack) { + if ( timer_ack ) + { /* * Subtle, when I/O APICs are used we have to ack timer IRQ manually * to reset the IRR bit for do_slow_gettimeoffset(). This will also * deassert NMI lines for the watchdog if run on an 82489DX-based * system. */ + extern spinlock_t i8259A_lock; spin_lock(&i8259A_lock); outb(0x0c, 0x20); /* Ack the IRQ; AEOI will end it automatically. */ @@ -102,6 +116,8 @@ static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, static unsigned long __init calibrate_tsc(void) { + unsigned long startlow, starthigh, endlow, endhigh, count; + /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); @@ -116,44 +132,25 @@ static unsigned long __init calibrate_tsc(void) outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ - { - unsigned long startlow, starthigh; - unsigned long endlow, endhigh; - unsigned long count; - - rdtsc(startlow,starthigh); - count = 0; - do { - count++; - } while ((inb(0x61) & 0x20) == 0); - rdtsc(endlow,endhigh); - - /* Error: ECTCNEVERSET */ - if (count <= 1) - goto bad_ctc; - - /* 64-bit subtract - gcc just messes up with long longs */ - __asm__("subl %2,%0\n\t" - "sbbl %3,%1" - :"=a" (endlow), "=d" (endhigh) - :"g" (startlow), "g" (starthigh), - "0" (endlow), "1" (endhigh)); - - /* Error: ECPUTOOFAST */ - if (endhigh) - goto bad_ctc; - - return endlow; - } + rdtsc(startlow, starthigh); + for ( count = 0; (inb(0x61) & 0x20) == 0; count++ ) + continue; + rdtsc(endlow, endhigh); - /* - * The CTC wasn't reliable: we got a hit on the very first read, or the CPU - * was so fast/slow that the quotient wouldn't fit in 32 bits.. - */ - bad_ctc: - return 0; + /* Error if the CTC doesn't behave itself. */ + if ( count == 0 ) + return 0; + + /* [endhigh:endlow] = [endhigh:endlow] - [starthigh:startlow] */ + __asm__( "subl %2,%0 ; sbbl %3,%1" + : "=a" (endlow), "=d" (endhigh) + : "g" (startlow), "g" (starthigh), "0" (endlow), "1" (endhigh) ); + + /* If quotient doesn't fit in 32 bits then we return error (zero). */ + return endhigh ? 0 : endlow; } + /*************************************************************************** * CMOS Timer functions ***************************************************************************/ @@ -178,32 +175,32 @@ mktime (unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec) { - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ + /* 1..12 -> 11,12,1..10: put Feb last since it has a leap day. */ + if ( 0 >= (int) (mon -= 2) ) + { + mon += 12; year -= 1; } + return ((((unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day)+ year*365 - 719499 )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ + )*60 + min /* now have minutes */ )*60 + sec; /* finally seconds */ } static unsigned long __get_cmos_time(void) { unsigned int year, mon, day, hour, min, sec; - /* Linux waits here for a the Update-In-Progress (UIP) flag going - * from 1 to 0. This can take up to a second. This is not acceptable - * for the use in Xen and this code is therfor removed at the cost - * of reduced accuracy. */ - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); + + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + if ( !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD ) { BCD_TO_BIN(sec); BCD_TO_BIN(min); @@ -213,7 +210,7 @@ static unsigned long __get_cmos_time(void) BCD_TO_BIN(year); } - if ((year += 1900) < 1970) + if ( (year += 1900) < 1970 ) year += 100; return mktime(year, mon, day, hour, min, sec); @@ -239,42 +236,33 @@ static unsigned long maybe_get_cmos_time(void) return retval; } -/* the more accurate version waits for a change */ +/* This version spins until it definitely reads a valid time from CMOS RAM. */ static unsigned long get_cmos_time(void) { unsigned long res, flags; int i; spin_lock_irqsave(&rtc_lock, flags); - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ + /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + for ( i = 0 ; i < 1000000 ; i++ ) /* may take up to 1 second... */ + if ( (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) ) break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + for ( i = 0 ; i < 1000000 ; i++ ) /* must try at least 2.228 ms */ + if ( !(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) ) break; + res = __get_cmos_time(); + spin_unlock_irqrestore(&rtc_lock, flags); return res; } + /*************************************************************************** - * Time - * XXX RN: Will be able to remove some of the locking once the time is - * update by the APIC on only one CPU. + * System Time ***************************************************************************/ -static spinlock_t stime_lock; -static u32 st_scale_f; -static u32 st_scale_i; -u32 stime_pcc; /* cycle counter value at last timer irq */ -s_time_t stime_now; /* time in ns at last timer IRQ */ - static inline s_time_t __get_s_time(void) { s32 delta_tsc; @@ -283,13 +271,13 @@ static inline s_time_t __get_s_time(void) rdtscll(tsc); low = (u32)(tsc >> rdtsc_bitshift); - delta_tsc = (s32)(low - stime_pcc); + delta_tsc = (s32)(low - tsc_irq); if ( unlikely(delta_tsc < 0) ) delta_tsc = 0; delta = ((u64)delta_tsc * st_scale_f); delta >>= 32; delta += ((u64)delta_tsc * st_scale_i); - return stime_now + delta; + return stime_irq + delta; } s_time_t get_s_time(void) @@ -303,25 +291,23 @@ s_time_t get_s_time(void) } -/* Wall Clock time */ -struct timeval wall_clock_time; /* wall clock time at last update */ -s_time_t wctime_st; /* system time at last update */ - void do_gettimeofday(struct timeval *tv) { unsigned long flags; unsigned long usec, sec; spin_lock_irqsave(&stime_lock, flags); - usec = ((unsigned long)(__get_s_time() - wctime_st))/1000; + usec = ((unsigned long)(__get_s_time() - stime_irq))/1000; sec = wall_clock_time.tv_sec; usec += wall_clock_time.tv_usec; spin_unlock_irqrestore(&stime_lock, flags); - while (usec >= 1000000) { + while ( usec >= 1000000 ) + { usec -= 1000000; sec++; } + tv->tv_sec = sec; tv->tv_usec = usec; } @@ -331,11 +317,11 @@ void do_settimeofday(struct timeval *tv) printk("XXX: do_settimeofday not implemented\n"); } + /*************************************************************************** * Update times ***************************************************************************/ -/* update a domains notion of time */ void update_dom_time(shared_info_t *si) { unsigned long flags; @@ -343,15 +329,13 @@ void update_dom_time(shared_info_t *si) spin_lock_irqsave(&stime_lock, flags); si->cpu_freq = cpu_freq; si->rdtsc_bitshift = rdtsc_bitshift; - si->system_time = stime_now; - si->st_timestamp = stime_pcc; + si->system_time = stime_irq; + si->st_timestamp = tsc_irq; si->tv_sec = wall_clock_time.tv_sec; si->tv_usec = wall_clock_time.tv_usec; - si->wc_timestamp = wctime_st; + si->wc_timestamp = stime_irq; si->wc_version++; spin_unlock_irqrestore(&stime_lock, flags); - - TRC(printk(" 0x%08X%08X\n", (u32)(wctime_st>>32), (u32)wctime_st)); } /* @@ -362,21 +346,12 @@ void update_dom_time(shared_info_t *si) * - index 0 -> go slower * - index 1 -> frequency as determined during calibration * - index 2 -> go faster - */ -/* - * NB. The period is not a whole number of seconds since we want to avoid - * being in sync with the CMOS update-in-progress flag, which causes this - * routine to bail. - */ -/* + * * NB2. Note that update_scale is called from update_time with the stime_lock * still held. This is because we must only slow down cpu_freq at a timebase * change. If we did it in the middle of an update period then time would * seem to jump backwards since BASE+OLD_FREQ*DIFF > BASE+NEW_FREQ*DIFF. */ -#define SCALE_UPDATE_PERIOD MILLISECS(50200) -static unsigned long init_cmos_time; -static u64 cpu_freqs[3]; static void update_scale(void) { unsigned long cmos_time; @@ -389,15 +364,18 @@ static void update_scale(void) return; ct = (u32)(cmos_time - init_cmos_time); - st = (u32)(stime_now/SECONDS(1)); + st = (u32)(stime_irq/SECONDS(1)); dt = (s32)(ct - st); - /* work out adjustment to scaling factor. allow +/- 1s drift */ - if (dt < -1) freq_index = 0; /* go slower */ - else if (dt > 1) freq_index = 2; /* go faster */ - else freq_index = 1; /* correct speed */ + /* Work out adjustment to scaling factor. Allow +/- 1s drift. */ + if ( dt < -1 ) + freq_index = 0; /* go slower */ + else if ( dt > 1 ) + freq_index = 2; /* go faster */ + else + freq_index = 1; /* correct speed */ - if ((dt <= -10) || (dt >= 10)) + if ( (dt <= -10) || (dt >= 10) ) printk("Large time drift (cmos time - system time = %ds)\n", dt); /* set new frequency */ @@ -411,36 +389,32 @@ static void update_scale(void) } -/* - * Update hypervisors notion of time - * This is done periodically of it's own timer - */ -#define TIME_UPDATE_PERIOD MILLISECS(200) -static struct ac_timer update_timer; -static void update_time(unsigned long foo) +static void update_time(unsigned long unused) { unsigned long flags; s_time_t new_st; unsigned long usec; - u64 full_pcc; + u64 full_tsc; static int calls_since_scale_update = 0; spin_lock_irqsave(&stime_lock, flags); - /* Update system time. */ - stime_now = new_st = __get_s_time(); - rdtscll(full_pcc); - stime_pcc = (u32)(full_pcc >> rdtsc_bitshift); + rdtscll(full_tsc); + new_st = __get_s_time(); /* Update wall clock time. */ - usec = ((unsigned long)(new_st - wctime_st))/1000; + usec = ((unsigned long)(new_st - stime_irq))/1000; usec += wall_clock_time.tv_usec; - while (usec >= 1000000) { + while ( usec >= 1000000 ) + { usec -= 1000000; wall_clock_time.tv_sec++; } wall_clock_time.tv_usec = usec; - wctime_st = new_st; + + /* Update system time. */ + stime_irq = new_st; + tsc_irq = (u32)(full_tsc >> rdtsc_bitshift); /* Maybe update our rate to be in sync with the RTC. */ if ( ++calls_since_scale_update >= @@ -452,8 +426,8 @@ static void update_time(unsigned long foo) spin_unlock_irqrestore(&stime_lock, flags); - TRC(printk("TIME[%02d] update time: stime_now=%lld now=%lld,wct=%ld:%ld\n", - smp_processor_id(), stime_now, new_st, wall_clock_time.tv_sec, + TRC(printk("TIME[%02d] update time: stime_irq=%lld now=%lld,wct=%ld:%ld\n", + smp_processor_id(), stime_irq, new_st, wall_clock_time.tv_sec, wall_clock_time.tv_usec)); /* Reload the timer. */ @@ -462,17 +436,12 @@ static void update_time(unsigned long foo) } -/*************************************************************************** - * Init Xeno Time - * This has to be done after all CPUs have been booted - ***************************************************************************/ +/* Late init function (after all CPUs are booted). */ int __init init_xeno_time() { - int cpu = smp_processor_id(); - u32 cpu_cycle; /* time of one cpu cyle in pico-seconds */ - u64 scale; /* scale factor */ + u64 scale; s64 freq_off; - u64 full_pcc; + u64 full_tsc; unsigned int cpu_ghz; spin_lock_init(&stime_lock); @@ -481,61 +450,47 @@ int __init init_xeno_time() for ( rdtsc_bitshift = 0; cpu_ghz != 0; rdtsc_bitshift++, cpu_ghz >>= 1 ) continue; - printk("Init Time[%02d]: %u\n", cpu, rdtsc_bitshift); - - /* System Time */ - cpu_cycle = (u32) (1000000000LL/cpu_khz); /* in pico seconds */ - - /* calculate adjusted frequencies */ - freq_off = cpu_freq/1000; /* .1% */ + /* Calculate adjusted frequencies: +/- 0.1% */ + freq_off = cpu_freq/1000; cpu_freqs[0] = cpu_freq + freq_off; cpu_freqs[1] = cpu_freq; cpu_freqs[2] = cpu_freq - freq_off; - scale = 1000000000LL << (32 + rdtsc_bitshift); + scale = 1000000000LL << (32 + rdtsc_bitshift); scale /= cpu_freq; st_scale_f = scale & 0xffffffff; st_scale_i = scale >> 32; - /* Wall Clock time */ - wall_clock_time.tv_sec = get_cmos_time(); - wall_clock_time.tv_usec = 0; - - /* init cmos_time for synchronising */ - init_cmos_time = wall_clock_time.tv_sec; + /* System time ticks from zero. */ + rdtscll(full_tsc); + stime_irq = (s_time_t)0; + tsc_irq = (u32)(full_tsc >> rdtsc_bitshift); - /* set starting times */ - stime_now = (s_time_t)0; - rdtscll(full_pcc); - stime_pcc = (u32)(full_pcc >> rdtsc_bitshift); - wctime_st = NOW(); + /* Wallclock time starts as the initial RTC time. */ + wall_clock_time.tv_sec = init_cmos_time = get_cmos_time(); + wall_clock_time.tv_usec = 0; - /* start timer to update time periodically */ + /* Start timer to periodically update time and frequency scale. */ init_ac_timer(&update_timer, 0); update_timer.data = 1; update_timer.function = &update_time; update_time(0); - printk(".... System Time: %lldns\n", NOW()); - printk(".....cpu_freq: %08X%08X\n", (u32)(cpu_freq>>32), (u32)cpu_freq); - printk(".....cpu_cycle: %u ps\n", cpu_cycle); - printk(".....scale: %08X%08X\n", (u32)(scale>>32), (u32)scale); - printk(".... st_scale_f: %X\n", st_scale_f); - printk(".... st_scale_i: %X\n", st_scale_i); - printk(".... stime_pcc: %u\n", stime_pcc); - - printk(".... Wall Clock: %lds %ldus\n", wall_clock_time.tv_sec, - wall_clock_time.tv_usec); - printk(".... wctime_st: %lld\n", wctime_st); + printk("Time init:\n"); + printk(".... System Time: %lldns\n", + NOW()); + printk(".... cpu_freq: %08X:%08X\n", + (u32)(cpu_freq>>32), (u32)cpu_freq); + printk(".... scale: %08X:%08X\n", + (u32)(scale>>32), (u32)scale); + printk(".... Wall Clock: %lds %ldus\n", + wall_clock_time.tv_sec, wall_clock_time.tv_usec); return 0; } -/*************************************************************************** - * Init - ***************************************************************************/ - +/* Early init function. */ void __init time_init(void) { unsigned long ticks_per_frac = calibrate_tsc(); diff --git a/xen/common/ac_timer.c b/xen/common/ac_timer.c index 1e5d3f6bcd..a34d8f12c7 100644 --- a/xen/common/ac_timer.c +++ b/xen/common/ac_timer.c @@ -1,20 +1,15 @@ /* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- **************************************************************************** - * (C) 2002 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2002-2003 University of Cambridge **************************************************************************** * * File: ac_timer.c * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk) - * Changes: + * Keir Fraser (kaf24@cl.cam.ac.uk) * - * Date: Nov 2002 - * * Environment: Xen Hypervisor * Description: Accurate timer for the Hypervisor - * - **************************************************************************** - * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $ - **************************************************************************** */ #include @@ -38,10 +33,10 @@ #define TRC(_x) #endif -/***************************************************************************** +/* * We pull handlers off the timer list this far in future, * rather than reprogramming the time hardware. - *****************************************************************************/ + */ #define TIMER_SLOP (50*1000) /* ns */ /* A timer list per CPU */ @@ -65,24 +60,29 @@ static inline unsigned long __add_ac_timer(struct ac_timer *timer) /* * Add timer to the list. If it gets added to the front we schedule * a softirq. This will reprogram the timer, or handle the timer event - * imemdiately, depending on whether alarm is sufficiently ahead in the + * immediately, depending on whether alarm is sufficiently ahead in the * future. */ - if (list_empty(&ac_timers[cpu].timers)) { + if ( list_empty(&ac_timers[cpu].timers) ) + { list_add(&timer->timer_list, &ac_timers[cpu].timers); goto send_softirq; - } else { + } + else + { struct list_head *pos; struct ac_timer *t; - list_for_each(pos, &ac_timers[cpu].timers) { + list_for_each ( pos, &ac_timers[cpu].timers ) + { t = list_entry(pos, struct ac_timer, timer_list); - if (t->expires > timer->expires) + if ( t->expires > timer->expires ) break; } + list_add(&(timer->timer_list), pos->prev); - if (timer->timer_list.prev == &ac_timers[cpu].timers) + if ( timer->timer_list.prev == &ac_timers[cpu].timers ) goto send_softirq; } @@ -104,7 +104,8 @@ void add_ac_timer(struct ac_timer *timer) cpu_mask = __add_ac_timer(timer); spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - if ( cpu_mask ) smp_send_event_check_mask(cpu_mask); + if ( cpu_mask ) + smp_send_event_check_mask(cpu_mask); } @@ -135,11 +136,15 @@ static inline unsigned long __rem_ac_timer(struct ac_timer *timer) detach_ac_timer(timer); - if (timer->timer_list.prev == &ac_timers[cpu].timers) { + if ( timer->timer_list.prev == &ac_timers[cpu].timers ) + { /* just removed the head */ - if (list_empty(&ac_timers[cpu].timers)) { + if ( list_empty(&ac_timers[cpu].timers) ) + { goto send_softirq; - } else { + } + else + { timer = list_entry(ac_timers[cpu].timers.next, struct ac_timer, timer_list); if ( timer->expires > (NOW() + TIMER_SLOP) ) @@ -165,7 +170,8 @@ void rem_ac_timer(struct ac_timer *timer) cpu_mask = __rem_ac_timer(timer); spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - if ( cpu_mask ) smp_send_event_check_mask(cpu_mask); + if ( cpu_mask ) + smp_send_event_check_mask(cpu_mask); } @@ -192,7 +198,8 @@ void mod_ac_timer(struct ac_timer *timer, s_time_t new_time) spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - if ( cpu_mask ) smp_send_event_check_mask(cpu_mask); + if ( cpu_mask ) + smp_send_event_check_mask(cpu_mask); } @@ -214,25 +221,31 @@ void do_ac_timer(void) TRC(printk("ACT [%02d] do(): now=%lld\n", cpu, NOW())); /* Sanity: is the timer list empty? */ - if ( list_empty(&ac_timers[cpu].timers) ) goto out; + if ( list_empty(&ac_timers[cpu].timers) ) + goto out; /* Handle all timeouts in the near future. */ while ( !list_empty(&ac_timers[cpu].timers) ) { t = list_entry(ac_timers[cpu].timers.next,struct ac_timer, timer_list); - if ( t->expires > (NOW() + TIMER_SLOP) ) break; + if ( t->expires > (NOW() + TIMER_SLOP) ) + break; ASSERT(t->cpu == cpu); - /* do some stats */ + /* Do some stats collection. */ diff = (now - t->expires); - if (diff > 0x7fffffff) diff = 0x7fffffff; /* THIS IS BAD! */ + if ( diff > 0x7fffffff ) + diff = 0x7fffffff; /* THIS IS BAD! */ max = perfc_valuea(ac_timer_max, cpu); - if (diff > max) perfc_seta(ac_timer_max, cpu, diff); + if ( diff > max ) + perfc_seta(ac_timer_max, cpu, diff); detach_ac_timer(t); + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - if ( t->function != NULL ) t->function(t->data); + if ( t->function != NULL ) + t->function(t->data); spin_lock_irqsave(&ac_timers[cpu].lock, flags); } @@ -246,7 +259,9 @@ void do_ac_timer(void) TRC(printk("ACT [%02d] do(): again\n", cpu)); goto do_timer_again; } - } else { + } + else + { reprogram_ac_timer((s_time_t) 0); } @@ -288,10 +303,7 @@ static void ac_timer_softirq_action(struct softirq_action *a) } } -/***************************************************************************** - * debug dump_queue - * arguments: queue head, name of queue - *****************************************************************************/ + static void dump_tqueue(struct list_head *queue, char *name) { struct list_head *list; @@ -300,7 +312,9 @@ static void dump_tqueue(struct list_head *queue, char *name) printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); - list_for_each (list, queue) { + + list_for_each ( list, queue ) + { t = list_entry(list, struct ac_timer, timer_list); printk (" %s %d : %lx ex=0x%08X%08X %lu n: %lx, p: %lx\n", name, loop++, @@ -308,10 +322,10 @@ static void dump_tqueue(struct list_head *queue, char *name) (u32)(t->expires>>32), (u32)t->expires, t->data, (unsigned long)list->next, (unsigned long)list->prev); } - return; } -void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs) + +static void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs) { u_long flags; s_time_t now = NOW(); @@ -319,14 +333,15 @@ void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs) printk("Dumping ac_timer queues: NOW=0x%08X%08X\n", (u32)(now>>32), (u32)now); - for (i = 0; i < smp_num_cpus; i++) { + + for ( i = 0; i < smp_num_cpus; i++ ) + { printk("CPU[%02d] ", i); spin_lock_irqsave(&ac_timers[i].lock, flags); dump_tqueue(&ac_timers[i].timers, "ac_time"); spin_unlock_irqrestore(&ac_timers[i].lock, flags); printk("\n"); } - return; } @@ -343,52 +358,6 @@ void __init ac_timer_init(void) INIT_LIST_HEAD(&ac_timers[i].timers); spin_lock_init(&ac_timers[i].lock); } -} - -/***************************************************************************** - * GRAVEYARD - *****************************************************************************/ - -#if 0 - -#ifdef AC_TIMER_STATS -#define BUCKETS 1000 -#define MAX_STATS -typedef struct act_stats_st -{ - u32 count; - u32 times[2*(BUCKETS)]; -} __cacheline_aligned act_stats_t; -static act_stats_t act_stats[NR_CPUS]; - -#endif - -#ifdef AC_TIMER_STATS - { - XXX this is at the wrong place - s32 diff; - u32 i; - diff = ((s32)(NOW() - t->expires)) / 1000; /* delta in us */ - if (diff < -BUCKETS) - diff = -BUCKETS; - else if (diff > BUCKETS) - diff = BUCKETS; - act_stats[cpu].times[diff+BUCKETS]++; - act_stats[cpu].count++; - - if (act_stats[cpu].count >= 5000) { - printk("ACT Stats\n"); - for (i=0; i < 2*BUCKETS; i++) { - if (act_stats[cpu].times[i] != 0) - printk("ACT [%02d]: %3dus: %5d\n", - cpu,i-BUCKETS, act_stats[cpu].times[i]); - act_stats[cpu].times[i]=0; - } - act_stats[cpu].count = 0; - printk("\n"); - } - } -#endif - -#endif /* 0 */ + add_key_handler('a', dump_timerq, "dump ac_timer queues"); +} diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index 261e6fbb79..b3d3631777 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -116,7 +116,6 @@ void do_task_queues(u_char key, void *dev_id, struct pt_regs *regs) extern void perfc_printall (u_char key, void *dev_id, struct pt_regs *regs); extern void perfc_reset (u_char key, void *dev_id, struct pt_regs *regs); -extern void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs); extern void dump_runq(u_char key, void *dev_id, struct pt_regs *regs); extern void print_sched_histo(u_char key, void *dev_id, struct pt_regs *regs); extern void reset_sched_histo(u_char key, void *dev_id, struct pt_regs *regs); @@ -131,7 +130,6 @@ void initialize_keytable() key_table[i].handler = (key_handler *)NULL; /* setup own handlers */ - add_key_handler('a', dump_timerq, "dump ac_timer queues"); add_key_handler('d', dump_registers, "dump registers"); add_key_handler('h', show_handlers, "show this message"); add_key_handler('l', print_sched_histo, "print sched latency histogram"); diff --git a/xen/include/asm-i386/time.h b/xen/include/asm-i386/time.h index 9c9ae87182..40145ddb0f 100644 --- a/xen/include/asm-i386/time.h +++ b/xen/include/asm-i386/time.h @@ -5,16 +5,9 @@ * * File: time.h * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk) - * Changes: - * - * Date: Nov 2002 * * Environment: Xen Hypervisor * Description: Architecture dependent definition of time variables - * - **************************************************************************** - * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $ - **************************************************************************** */ #ifndef _ASM_TIME_H_ @@ -23,28 +16,7 @@ #include #include -/* - * Cycle Counter Time - */ -typedef u64 cc_time_t; -static inline cc_time_t get_cc_time() -{ - u64 ret; - rdtscll(ret); - return ret; -} - -/* - * System Time - */ -typedef s64 s_time_t; /* System time */ -extern u32 stime_pcc; /* cycle counter value at last timer irq */ -extern s_time_t stime_now; /* time in ns at last timer IRQ */ - -/* - * Domain Virtual Time - */ -typedef u64 dv_time_t; +typedef s64 s_time_t; /* system time */ extern int using_apic_timer; -- 2.30.2